package com.leo.entity;

import com.almasb.fxgl.core.math.FXGLMath;
import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.dsl.components.EffectComponent;
import com.almasb.fxgl.dsl.components.ExpireCleanComponent;
import com.almasb.fxgl.dsl.components.HealthIntComponent;
import com.almasb.fxgl.dsl.components.ProjectileComponent;
import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.entity.EntityFactory;
import com.almasb.fxgl.entity.SpawnData;
import com.almasb.fxgl.entity.Spawns;
import com.almasb.fxgl.entity.components.CollidableComponent;
import com.almasb.fxgl.physics.BoundingShape;
import com.almasb.fxgl.texture.AnimatedTexture;
import com.almasb.fxgl.texture.AnimationChannel;
import com.almasb.fxgl.ui.ProgressBar;
import com.leo.common.Config;
import com.leo.common.GameType;
import com.leo.common.ItemType;
import com.leo.component.EnemyComponent;
import com.leo.component.FlagComponent;
import com.leo.component.TankComponent;
import com.leo.component.TankLevelComponent;
import javafx.geometry.Point2D;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;

public class PlayerEntityFactory implements EntityFactory {

    @Spawns("player")
    public Entity createPlayer(SpawnData spawnData) {
        // 生命值组件
        HealthIntComponent healthIntComponent = new HealthIntComponent(5);
        healthIntComponent.setValue(5);
        // 生命进度条
        ProgressBar hpBar = new ProgressBar(false);
        hpBar.setLabelVisible(false);
        // 调整进度条大小和位置
        hpBar.setWidth(39);
        hpBar.setHeight(8);
        hpBar.setTranslateY(39);
        hpBar.setFill(Color.LIGHTGREEN);
        // 根据血量改变进度条颜色
        hpBar.currentValueProperty().addListener((observable, oldValue, newValue) -> {
            int value = newValue.intValue();
            switch (value) {
                case 1, 2 -> hpBar.setFill(Color.RED);
                case 3 -> hpBar.setFill(Color.LIGHTYELLOW);
                default -> hpBar.setFill(Color.LIGHTGREEN);
            }
        });
        // 和生命值组件绑定
        hpBar.maxValueProperty().bind(healthIntComponent.maxValueProperty());
        hpBar.currentValueProperty().bind(healthIntComponent.valueProperty());

        return FXGL.entityBuilder(spawnData)
                .type(GameType.PLAYER)
                .viewWithBBox(FXGL.texture("tank/H1U.png"))
                .view(hpBar)
                .with(new EffectComponent())
                .with(new TankComponent())
                .with(healthIntComponent)
                .with(new TankLevelComponent())
                .with(new CollidableComponent(true))
                .build();
    }

    /**
     * 雪地
     *
     * @param spawnData
     * @return
     */
    @Spawns("snow")
    public Entity createSnow(SpawnData spawnData) {
        return FXGL.entityBuilder(spawnData)
                .type(GameType.SNOW)
                .bbox(BoundingShape.box(Config.CELL_SIZE, Config.CELL_SIZE))
                .collidable()
                .neverUpdated()
                .build();
    }

    /**
     * 草坪
     *
     * @param spawnData
     * @return
     */
    @Spawns("greens")
    public Entity createGreens(SpawnData spawnData) {
        // 从地图中获取
        int width = spawnData.get("width");
        int height = spawnData.get("height");
        return FXGL.entityBuilder(spawnData)
                .type(GameType.GREENS)
                .bbox(BoundingShape.box(width, height))
                .collidable()
                .zIndex(100)
                .neverUpdated()
                .build();
    }

    /**
     * 水
     *
     * @param spawnData
     * @return
     */
    @Spawns("sea")
    public Entity createSea(SpawnData spawnData) {
        AnimationChannel ac = new AnimationChannel(FXGL.image("map/sea_anim.png"), Duration.seconds(1), 2);
        AnimatedTexture at = new AnimatedTexture(ac);
        return FXGL.entityBuilder(spawnData)
                .type(GameType.SEA)
                .viewWithBBox(at.loop())
                .collidable()
                .build();
    }

    /**
     * 石头
     *
     * @param spawnData
     * @return
     */
    @Spawns("stone")
    public Entity createStone(SpawnData spawnData) {
        return FXGL.entityBuilder(spawnData)
                .type(GameType.STONE)
                .bbox(BoundingShape.box(Config.CELL_SIZE, Config.CELL_SIZE))
                .collidable()
                .neverUpdated()
                .build();
    }

    /**
     * 土墙
     *
     * @param spawnData
     * @return
     */
    @Spawns("brick")
    public Entity createBrick(SpawnData spawnData) {
        return FXGL.entityBuilder(spawnData)
                .type(GameType.BRICK)
                // 如果使用地图，这里使用bbox即可，因为view已经有了
                .bbox(BoundingShape.box(Config.CELL_SIZE, Config.CELL_SIZE))
                .collidable()
                .neverUpdated()
                .build();
    }

    /**
     * 边界
     *
     * @param spawnData
     * @return
     */
    @Spawns("border")
    public Entity createBorder(SpawnData spawnData) {
        int width = spawnData.get("width");
        int height = spawnData.get("height");
        return FXGL.entityBuilder(spawnData)
                .type(GameType.BORDER)
                .viewWithBBox(new Rectangle(width, height, Color.LIGHTGRAY))
                .collidable()
                .neverUpdated()
                .build();
    }

    @Spawns("bullet")
    public Entity createBullet(SpawnData spawnData) {
        FXGL.play("normalFire.wav");
        Point2D dir = spawnData.get("dir");
        // 忽略同阵营的子弹碰撞效果
        CollidableComponent collidableComponent = new CollidableComponent(true);
        collidableComponent.addIgnoredType(spawnData.get("ownerType"));
        return FXGL.entityBuilder(spawnData)
                .type(GameType.BULLET)
                .viewWithBBox("bullet/normal.png")
                .with(new ProjectileComponent(dir, Config.BULLET_SPEED))
                .with(collidableComponent)
                .build();
    }

    /**
     * 敌人
     *
     * @param spawnData
     * @return
     */
    @Spawns("enemy")
    public Entity createEnemy(SpawnData spawnData) {
        return FXGL.entityBuilder(spawnData)
                .type(GameType.ENEMY)
                .viewWithBBox(FXGL.texture("tank/E" + FXGL.random(1, 12) + "U.png"))
                .with(new EffectComponent())
                .with(new TankComponent())
                .with(new EnemyComponent())
                .with(new TankLevelComponent())
                .with(new CollidableComponent(true))
                .build();
    }

    /**
     * 爆炸效果
     *
     * @param spawnData
     * @return
     */
    @Spawns("explode")
    public Entity createExplode(SpawnData spawnData) {
        FXGL.play("normalBomb.wav");
        AnimationChannel ac = new AnimationChannel(FXGL.image("explode/explode_level_2.png"), Duration.seconds(0.5), 9);
        AnimatedTexture at = new AnimatedTexture(ac);
        return FXGL.entityBuilder(spawnData)
                .view(at.play())
                .with(new ExpireCleanComponent(Duration.seconds(0.5)))
                .build();
    }

    /**
     * 敌人自爆
     *
     * @param spawnData
     * @return
     */
    @Spawns("bomb")
    public Entity createBomb(SpawnData spawnData) {
        FXGL.play("rocketBomb.wav");
        AnimationChannel ac = new AnimationChannel(FXGL.image("explode/explode_level_1.png"), Duration.seconds(0.5), 5);
        AnimatedTexture at = new AnimatedTexture(ac);
        return FXGL.entityBuilder(spawnData)
                .view(at.play())
                .with(new ExpireCleanComponent(Duration.seconds(0.5)))
                .build();
    }

    /**
     * 道具
     *
     * @param spawnData
     * @return
     */
    @Spawns("item")
    public Entity createItem(SpawnData spawnData) {
        ItemType itemType = FXGLMath.random(ItemType.values()).get();
        spawnData.put("itemType", itemType);
        return FXGL.entityBuilder(spawnData)
                .type(GameType.ITEM)
                .viewWithBBox("item/" + itemType.toString().toLowerCase() + ".png")
                .with(new ExpireCleanComponent(Duration.seconds(25)))
                .collidable()
                .build();
    }

    @Spawns("flag")
    public Entity createFlag(SpawnData spawnData) {
        return FXGL.entityBuilder(spawnData)
                .type(GameType.FLAG)
                .bbox(BoundingShape.box(48, 48))
                .with(new FlagComponent())
                .collidable()
                .build();
    }
}
